package qy.jalgotrade.bar;

import java.io.Serializable;
import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * A Bar is a summary of the trading activity for a security in a given period.
 * 
 * @author qy
 *
 */
public abstract class Bar implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = -6676173225785956251L;

	/**
	 * <pre>
	 * Enum like class for bar frequencies. Valid values are:
	 * 
	 * **Frequency.TRADE**: The bar represents a single trade.
	 * **Frequency.SECOND**: The bar summarizes the trading activity during 1 second.
	 * **Frequency.MINUTE**: The bar summarizes the trading activity during 1 minute.
	 * **Frequency.HOUR**: The bar summarizes the trading activity during 1 hour.
	 * **Frequency.DAY**: The bar summarizes the trading activity during 1 day.
	 * **Frequency.WEEK**: The bar summarizes the trading activity during 1 week.
	 * **Frequency.MONTH**: The bar summarizes the trading activity during 1 month.
	 * </pre>
	 * 
	 * @author qy
	 *
	 */
	public enum Frequency {
		// @formatter:off
		// It is important for frequency values to get bigger for bigger windows.
		/**
		 * A single trade
		 */
		TRADE(-1),
		/**
		 * Tick
		 */
		TICK(-1),
//		LEVEL_I_SNAPSHOT_FUTURES_CN(0.5);
		/**
		 * 1 sec.
		 */
		SECOND(1),
		/**
		 * 3 sec.
		 */
		LEVEL_I_SNAPSHOT_STOCK_A(3),
		/**
		 * 6 sec.
		 */
		TICK_MONITOR_HIGH_LOAD(6),
		/**
		 * 12 sec.
		 */
		TICK_MONITOR_MEDIUM_LOAD(12),
		/**
		 * 30 sec.
		 */
		TICK_MONITOR_LOW_LOAD(30),
		/**
		 * 60 sec.
		 */
		MINUTE(60),
		/**
		 * 60 sec. (alias of {@link Frequency#MINUTE MINUTE})
		 */
		MINUTE_1(60), // alias of MINUTE
		/**
		 * 180 sec.
		 */
		MINUTE_3(180),
		/**
		 * 300 sec.
		 */
		MINUTE_5(300),
		/**
		 * 900 sec.
		 */
		MINUTE_15(900),
		/**
		 * 1,800 sec.
		 */
		MINUTE_30(1800),
		/**
		 * 3,600 sec.
		 */
		HOUR(3600),
		HOUR_2(7200),
		HOUR_4(14400),
		/**
		 * 24 * {@link Frequency#HOUR HOUR}
		 */
		DAY(86400), // 24 * HOUR
		/**
		 * 7 * {@link Frequency#DAY DAY}
		 */
		WEEK(604800), // 7 * DAY
		/**
		 * 31 * {@link Frequency#DAY DAY}
		 */
		MONTH(2678400), // 31 * DAY
		//
		MIN_1(1),
		MIN_3(3),
	    MIN_5(5),
	    MIN_10(10),
	    MIN_15(15),
	    MIN_30(30),
	    MIN_60(60),
	    MIN_120(120),
	    MIN_240(240);

		private static final List<Frequency> INTRADAY_FREQS_COMMON = Arrays.asList(
				MINUTE,
				MINUTE_3,
				MINUTE_5,
				MINUTE_15,
				MINUTE_30,
				HOUR);
		// @formatter:on

		private final int value;

		Frequency(int value) {

			this.value = value;
		}

		/**
		 *
		 * @return value
		 */
		public int getValue() {

			return value;
		}

		/**
		 *
		 * @return isIntraday
		 */
		public boolean isIntraday() {

			return getValue() < DAY.getValue();
		}

		/**
		 * 标准日内 Bar 频率: {min1, min3, min5, min15, min30, min60}
		 * 
		 * @return List&lt;Frequency&gt;
		 */
		public static List<Frequency> getIntradayFreqsCommon() {

			return INTRADAY_FREQS_COMMON;
		}
	}

	public abstract boolean getUseAdjValue();

	public abstract void setUseAdjustedValue(boolean useAdjustedValue);

	/**
	 * Returns the :class:`datetime.datetime`.<br />
	 * cmmt: 注意: getDateTime() 为 Bar 的 开始时间, 每个 Bar 汇总的市场信息包括当前 Bar 的 开始时点, 但不包括下个 Bar 的 开始时点, 即
	 * [currBar.getDateTime(), nextBar.getDateTime) (半开半闭 时间区间):
	 * 
	 * @return ZonedDateTime
	 */
	public abstract ZonedDateTime getDateTime();

	/**
	 * Returns the opening price.
	 * 
	 * @return open
	 */
	public double getOpen() {

		return getOpen(false);
	}

	/**
	 * Returns the opening price.
	 * 
	 * @param adjusted adjusted
	 * @return open
	 */
	public abstract double getOpen(boolean adjusted);

	/**
	 * Returns the highest price.
	 * 
	 * @return high
	 */
	public double getHigh() {

		return getHigh(false);
	}

	/**
	 * Returns the highest price.
	 * 
	 * @param adjusted adjusted
	 * @return high
	 */
	public abstract double getHigh(boolean adjusted);

	/**
	 * Returns the lowest price.
	 * 
	 * @return low
	 */
	public double getLow() {

		return getLow(false);
	}

	/**
	 * Returns the lowest price.
	 * 
	 * @param adjusted adjusted
	 * @return low
	 */
	public abstract double getLow(boolean adjusted);

	/**
	 * Returns the closing price.
	 * 
	 * @return close
	 */
	public double getClose() {

		return getClose(false);
	}

	/**
	 * Returns the closing price.
	 * 
	 * @param adjusted adjusted
	 * @return close
	 */
	public abstract double getClose(boolean adjusted);

	/**
	 * Returns the volume.
	 * 
	 * @return volume
	 */
	public abstract double getVolume();

	/**
	 * Returns the adjusted closing price.
	 * 
	 * @return adjusted closing price
	 */
	public abstract double getAdjClose();

	/**
	 * The bar's period.
	 * 
	 * @return Frequency
	 */
	public abstract Frequency getFrequency();

	/**
	 * Returns the typical price.
	 * 
	 * @return typical price
	 */
	public double getTypicalPrice() {

		return (getHigh() + getLow() + getClose()) / 3.0;
	}

	/**
	 * Returns the closing or adjusted closing price.
	 * 
	 * @return price
	 */
	public abstract double getPrice();

	public abstract Map<String, Double> getExtraColumns();
}
